
local function forcesuper(line, mo)
	
	//for mo in players.iterate
		if not (mo.player.charflags & SF_SUPER) // make sure anyone can turn super
            mo.player.charflags = $1 + SF_SUPER
		end
		if mo.player.powers[pw_super] == 0 and mo.player.rings > 0 then
			P_SpawnMobj(mo.x, mo.y, mo.z, MT_EMERALD1)
			P_SpawnMobj(mo.x, mo.y, mo.z, MT_EMERALD2)
			P_SpawnMobj(mo.x, mo.y, mo.z, MT_EMERALD3)
			P_SpawnMobj(mo.x, mo.y, mo.z, MT_EMERALD4)
			P_SpawnMobj(mo.x, mo.y, mo.z, MT_EMERALD5)
			P_SpawnMobj(mo.x, mo.y, mo.z, MT_EMERALD6)
			P_SpawnMobj(mo.x, mo.y, mo.z, MT_EMERALD7)
			mo.player.powers[pw_super] = 1 // turn supper
		end
		// damage player if they hve zero rings
		P_DamageMobj(mo, nil, nil, 0, DMG_NUKE)
	//end
	
end

addHook("LinedefExecute", forcesuper, "LUASUP")

----------------
-- circredux - Circuit Redux (waypoints and position tracking)
-- by fickleheart
--
-- This script is free to re-use.

--[[
	MAP SETUP:
	Use Fang Waypoints along the map's primary route (branching paths in waypoints are not supported yet)
	Angle - waypoint sequence # (skipping numbers is allowed, as long as each waypoint has a higher index than the previous)
	Parameter - starpost # (1-based) to reach before this waypoint is acknowledged (0 inherits from the previous waypoint, so this only needs set right at each starpost)
	Ambush flag - don't spawn extra waypoints between this and the next one (use this when waypoints cross pits or damaging sectors!)
	
	Starposts will no longer be used as respawn points or be visible/make noise, so you can safely apply them in damaging areas and such
	If you're having issues with waypoints going out of the expected order, try adding starposts to section them off as appropriate
]]

local VERSION = "1.0"

if circredux then
	assert(circredux.VERSION == VERSION, ("Multiple Circuit Redux versions loaded! (%d, tried to load %d) You may experience compatibility issues."):format(circredux.VERSION, VERSION))
	print("Circuit Redux is already loaded.")
	return
end -- Already defined!

print("\nCIRCUIT REDUX: version " .. VERSION)
print("by fickleheart, 2/16/2020\n")

rawset(_G, "circredux", {})

-- Need waypoints to think
mobjinfo[MT_FANGWAYPOINT].flags = $ & ~MF_NOTHINK

circredux.cv_tracker = CV_RegisterVar({"circredux_tracker", "On", 0, CV_OnOff})
circredux.cv_ranks = CV_RegisterVar({"circredux_ranks", "On", 0, CV_OnOff})
circredux.cv_debug = CV_RegisterVar({"circredux_debug", "Off", CV_NETVAR, CV_OnOff})

-- {x: fixed_t, y: fixed_t, z: fixed_t, angle: angle_t, starpost = int, backtrack = ?bool}
local checkpoints = {}
local standings = {}

addHook("NetVars", function(sync)
	checkpoints = sync(checkpoints)
	standings = sync(standings)
end)

local waypointstarpost

local dbgcolors = {SKINCOLOR_RED, SKINCOLOR_ORANGE, SKINCOLOR_YELLOW, SKINCOLOR_GREEN, SKINCOLOR_BLUE, SKINCOLOR_PURPLE}

local function DPrint(str)
	if circredux.cv_debug.value then
		print("\x84" .. "[CREDUX] \x80" .. str)
	end
end

local function AddCheckpoints(start, dest)
	local dist = P_AproxDistance(start.x - dest.x, start.y - dest.y)
	local numtoadd = (dist / (256*FRACUNIT)) or 1
	local angle = R_PointToAngle2(start.x, start.y, dest.x, dest.y)
	
	if start.spawnpoint.options & MTF_AMBUSH then -- Ambush: don't add waypoints between this and next
		numtoadd = 1
	end
	
	-- Add "backtrack" flag to checkpoints shortly before a starpost to prevent backtracking
	if #checkpoints > 4 and checkpoints[#checkpoints - 4].starpost == waypointstarpost - 1 and checkpoints[#checkpoints].starpost == waypointstarpost - 1 then
		checkpoints[#checkpoints - 4].backtrack = true
		
		if circredux.cv_debug.value then
			local dbg = P_SpawnMobj(checkpoints[#checkpoints - 4].x, checkpoints[#checkpoints - 4].y, checkpoints[#checkpoints - 4].z + 20*FRACUNIT, MT_GFZFLOWER1)
			dbg.flags = ($ | MF_NOCLIP|MF_NOCLIPTHING|MF_NOGRAVITY)
		end
	end
	
	for i = 0, numtoadd-1 do
		local x = start.x + FixedMul(dest.x - start.x, FixedDiv(i, numtoadd))
		local y = start.y + FixedMul(dest.y - start.y, FixedDiv(i, numtoadd))
		local z = start.z + FixedMul(dest.z - start.z, FixedDiv(i, numtoadd))
		
		z = P_FloorzAtPos(x, y, z + 50*FRACUNIT, 0)
		
		checkpoints[#checkpoints + 1] = {x = x, y = y, z = z, angle = angle, starpost = waypointstarpost}
		
		if circredux.cv_debug.value then
			local dbg = P_SpawnMobj(x, y, z, MT_BLUESPHERE)
			dbg.flags = ($ | MF_NOCLIP|MF_NOCLIPTHING) & ~(MF_SPECIAL)
			if smb then
				dbg.sprite = SPR_NMBR
				dbg.frame = (#checkpoints % 10) | FF_PAPERSPRITE
			end
			dbg.angle = angle - ANGLE_90
			dbg.color = dbgcolors[(waypointstarpost % #dbgcolors) + 1]
			dbg.colorized = true
		end
	end
	
	if dest.spawnpoint.extrainfo then
		waypointstarpost = dest.spawnpoint.extrainfo
	end
end

addHook("MapLoad", function()
	DPrint("Initializing waypoints...")

	checkpoints = {}
	waypointstarpost = 0
	local mapwaypoints = {}
	local lastwaypointnum = 0
	
	for mobj in mobjs.iterate() do
		if mobj.valid and mobj.spawnpoint and mobj.type == MT_FANGWAYPOINT then
			assert(not mapwaypoints[mobj.spawnpoint.angle], "Cannot have multiple waypoints with the same ID (" .. mobj.spawnpoint.angle .. ")")
			mapwaypoints[mobj.spawnpoint.angle] = mobj
			lastwaypointnum = max($, mobj.spawnpoint.angle)
		end
	end
	
	local firstwaypoint, pendingwaypoint
	
	for i = 0, lastwaypointnum do
		if not mapwaypoints[i] then continue end
		
		if not firstwaypoint then
			firstwaypoint = mapwaypoints[i]
			pendingwaypoint = firstwaypoint
		else
			AddCheckpoints(pendingwaypoint, mapwaypoints[i])
			pendingwaypoint = mapwaypoints[i]
		end
	end
	
	if firstwaypoint and pendingwaypoint then
		AddCheckpoints(pendingwaypoint, firstwaypoint)
	end
	
	DPrint(#checkpoints .. " waypoints created.")
	
	for player in players.iterate do
		player.checkpointtimes = {}
		player.checkpointprogress = 0
		player.wrongwayreference = 0
		player.wrongway = false
	end
end)

local function TrackCheckpointsAndStuff(player)
	local closestcheckpoint, closestdist, closestnum
	--print(player.starpostnum)
	
	for num, checkpoint in ipairs(checkpoints) do
		if checkpoint.starpost ~= player.starpostnum and not (checkpoint.starpost == player.starpostnum - 1 and checkpoint.backtrack) then continue end
		
		local dist = P_AproxDistance(player.mo.x - checkpoint.x, player.mo.y - checkpoint.y)
		
		if (not closestcheckpoint) or (dist < closestdist) then
			closestnum = num
			closestcheckpoint = checkpoint
			closestdist = dist
		end
	end
	
	if not closestcheckpoint then return end
	
	-- Force backtrack...
	if player.starpostnum ~= closestcheckpoint.starpost then
		DPrint(("Backtracking player %d (%s) to starpost number %d"):format(#player, player.name, closestcheckpoint.starpost))
		player.starpostnum = closestcheckpoint.starpost
	end
	
	if circredux.cv_debug.value and player.checkpointnum ~= closestnum then
		local dbg = P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z, MT_THOK)
		dbg.flags = $|MF_NOTHINK
		dbg.fuse = 65535
	end
	
	player.checkpointnum = closestnum
	
	if P_IsObjectOnGround(player.mo) and player.mo.health then
		player.starpostx = closestcheckpoint.x / FRACUNIT
		player.starposty = closestcheckpoint.y / FRACUNIT
		player.starpostz = closestcheckpoint.z / FRACUNIT
		player.starpostangle = closestcheckpoint.angle
	end
	
	if circredux.cv_debug.value then
		local dbg = P_SpawnMobj(closestcheckpoint.x, closestcheckpoint.y, closestcheckpoint.z + 20*FRACUNIT, MT_THOK)
		dbg.flags = ($ | MF_NOCLIP|MF_NOCLIPTHING) & ~(MF_SPECIAL)
		dbg.color = dbgcolors[(leveltime % #dbgcolors) + 1]
		dbg.fuse = 2
	end

	if not player.checkpointtimes then
		player.checkpointtimes = {}
		player.checkpointprogress = 0
	end

	local progress = player.laps * #checkpoints + ((not player.exiting) and player.checkpointnum or 0)
	
	while progress > player.checkpointprogress do
		player.checkpointprogress = $+1
		player.checkpointtimes[player.checkpointprogress] = leveltime
	end
	player.checkpointprogress = progress
	
	if player.checkpointtimes[player.checkpointprogress] < leveltime-32 and not player.exiting then
		player.checkpointtimes[player.checkpointprogress] = leveltime
	end
	
	-- Handle wrong way logic
	player.wrongwayreference = $ or 0
	if player.checkpointprogress - player.wrongwayreference > 1 then
		player.wrongwayreference = $+1
		player.wrongway = false
	elseif player.checkpointprogress - player.wrongwayreference < -1 then
		player.wrongwayreference = $-1
		player.wrongway = true
	end
	
	if not player.mo.health then -- Prevent WRONG WAY from showing up after death
		player.wrongwayreference = player.checkpointprogress - 20
	end
	
	-- Add to standings if not already present
	if player.circuitrank == nil then
		standings[#standings + 1] = player
	end
end

addHook("ThinkFrame", do
	if leveltime == 1 then
		mobjinfo[MT_STARPOST].painsound = (not (circuitmap and #checkpoints)) and sfx_strpst or sfx_none
		
		if circuitmap then
			for mo in mobjs.iterate() do
				if mo.type == MT_STARPOST then
					mo.flags = $ | MF_NOGRAVITY
					mo.flags2 = $ | MF2_DONTDRAW
				end
			end
		end
	end

	if not (circuitmap and #checkpoints) then return end
	
	for player in players.iterate do
		TrackCheckpointsAndStuff(player)
	end
	
	local i = 1
	while standings[i] do
		if not standings[i].valid then
			table.remove(standings, i)
			continue
		end
		
		-- Just in case............
		if standings[i] == standings[i-1] then
			table.remove(standings, i)
			continue
		end
		
		if i > 1 and standings[i-1].checkpointprogress < standings[i].checkpointprogress then
			standings[i-1], standings[i] = $2, $1
		end
		
		i = $+1
	end
	
	for k, v in ipairs(standings) do
		v.circuitrank = k
	end
end)

local function CompareTime(stplyr, comparing)
	if stplyr == comparing then
		return "", 0
	end
	
	local symbol, map, diff
	
	if stplyr.checkpointprogress >= comparing.checkpointprogress then
		symbol = "-"
		map = V_GREENMAP
		diff = (comparing.checkpointtimes[comparing.checkpointprogress] or 0) - (stplyr.checkpointtimes[comparing.checkpointprogress] or 0)
		
		if diff < 0 then
			if stplyr.checkpointprogress == comparing.checkpointprogress then -- Oops, flip it around
				symbol = "+"
				map = V_REDMAP
				diff = -$
			else -- No, just recompare with leveltime for the player that's behind...
				diff = leveltime - stplyr.checkpointtimes[comparing.checkpointprogress]
			end
		end
	else
		symbol = "+"
		map = V_REDMAP
		diff = stplyr.checkpointtimes[stplyr.checkpointprogress] - comparing.checkpointtimes[stplyr.checkpointprogress]
		
		if diff < 0 then -- No, just recompare with leveltime for the player that's behind...
			diff = leveltime - comparing.checkpointtimes[stplyr.checkpointprogress]
		end
	end
	
	return ("%s%d:%02d:%02d"):format(symbol, G_TicsToMinutes(diff, true), G_TicsToSeconds(diff), G_TicsToCentiseconds(diff)), map
end

local tweenx = {}
function circredux.DrawTracker(v, y, align)
	
	v.drawFill(0, y, 320, 2, align|4)
	
	y = $ + 6
	
	for i = #standings, 1, -1 do
		local player = standings[i]
		
		if not player.valid then continue end
	
		local patch, flip = v.getSprite2Patch(player.mo.skin, SPR2_LIFE, A, 1)
		local colormap = v.getColormap(player.mo.skin, player.skincolor)
		local x = ((player.checkpointnum or 0) * 2 - 1) * 320 / (#checkpoints * 2)
		
		if tweenx[#player] then
			x = $ + (tweenx[#player] - $)*7/8
		end
		tweenx[#player] = x
		
		if player == secondarydisplayplayer then
			v.drawScaled(x*FRACUNIT, y*FRACUNIT, FRACUNIT, patch, align|V_HUDTRANS|(flip and V_FLIP or 0), colormap)
		else
			local trans = (player ~= displayplayer) and V_HUDTRANSHALF or V_HUDTRANS
		
			v.drawScaled(x*FRACUNIT, y*FRACUNIT, FRACUNIT, patch, align|trans|(flip and V_FLIP or 0), colormap)
		end
	end
end

local hudflag = {lives = false, spec = false}
hud.add(function(v, stplyr)
	if circredux.HUD_OVERRIDE then return end
	
	-- Selective disabling of HUD elements
	local hudflag_lives = circuitmap and #checkpoints and circredux.cv_tracker.value
	local hudflag_spec = circuitmap and #checkpoints and (not stplyr.spectator)
	
	if hudflag_lives and not hudflag.lives then
		hudflag.lives = true
		hud.disable("lives")
	elseif hudflag.lives and not hudflag_lives then
		hud.enable("lives")
		hudflag.lives = false
	end
	
	if hudflag_spec and not hudflag.spec then
		hudflag.spec = true
		hud.disable("textspectator")
	elseif hudflag.spec and not hudflag_spec then
		hud.enable("textspectator")
		hudflag.spec = false
	end
	
	if not (circuitmap and #checkpoints) then
		return
	end
	
	-- Lap count
	local laptotal = CV_FindVar and CV_FindVar("numlaps").value or mapheaderinfo[gamemap].numlaps or 4
	if stplyr.laps < laptotal then
		v.drawString(306, 10, "LAP", V_SNAPTORIGHT|V_SNAPTOTOP|V_PERPLAYER|V_HUDTRANS|V_YELLOWMAP, "right")
		v.drawScaledNameTag((284 - v.nameTagWidth(stplyr.laps+1)/2) * FRACUNIT, 20*FRACUNIT, stplyr.laps+1, V_SNAPTORIGHT|V_SNAPTOTOP|V_PERPLAYER|V_HUDTRANS, FRACUNIT/2, SKINCOLOR_YELLOW, SKINCOLOR_FOREST)
		v.drawString(289, 22, "OF", V_SNAPTORIGHT|V_SNAPTOTOP|V_PERPLAYER|V_HUDTRANS|V_YELLOWMAP, "thin")
		v.drawScaledNameTag(300 * FRACUNIT, 20*FRACUNIT, laptotal, V_SNAPTORIGHT|V_SNAPTOTOP|V_PERPLAYER|V_HUDTRANS, FRACUNIT/2, SKINCOLOR_YELLOW, SKINCOLOR_FOREST)
	else
		v.drawScaledNameTag((315 - v.nameTagWidth("FINISHED")/2) * FRACUNIT, 20*FRACUNIT, "FINISHED", V_SNAPTORIGHT|V_SNAPTOTOP|V_PERPLAYER|V_HUDTRANS, FRACUNIT/2, SKINCOLOR_YELLOW, SKINCOLOR_FOREST)
	end
	
	-- Wrong way
	if stplyr.wrongway and (leveltime & 16) then
		v.drawNameTag(160, 120, "WRONG WAY", V_CENTERNAMETAG|V_PERPLAYER|V_HUDTRANS, SKINCOLOR_RED, SKINCOLOR_BLACK)
	end
	
	-- Position
	local circuitrank = stplyr.circuitrank or 1
	local rank = circuitrank .. (({"ST", "ND", "RD"})[circuitrank % ((circuitrank < 20) and 20 or 10)] or "TH")
	v.drawNameTag(315 - v.nameTagWidth(rank), 175 - circredux.cv_tracker.value * 15, rank, V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_PERPLAYER|V_HUDTRANS, SKINCOLOR_YELLOW, SKINCOLOR_FOREST)
	
	-- Rank listing
	if circredux.cv_ranks.value then
		local start = (stplyr.circuitrank or 1) - 2
		if start > #standings - 4 then
			start = #standings - 4
		end
		if start < 1 then
			start = 1
		end
		
		for key = 1, 5 do
			local player = standings[key + start - 1]
			
			if not player then break end
			if not player.valid then continue end
			
			local patch, flip = v.getSprite2Patch(player.mo.skin, SPR2_LIFE, A, 1)
			local colormap = v.getColormap(player.mo.skin, player.skincolor)
			
			local diff, map = CompareTime(stplyr, player)
			
			v.drawScaled(310*FRACUNIT, (60 + key*16)*FRACUNIT, FRACUNIT, patch, V_PERPLAYER|V_ALLOWLOWERCASE|V_SNAPTORIGHT|V_HUDTRANS|(flip and V_FLIP or 0), colormap)
			v.drawString(307, 50 + key*16, player.name, V_PERPLAYER|V_ALLOWLOWERCASE|V_SNAPTORIGHT|V_HUDTRANS, "thin-right")
			v.drawString(307, 57 + key*16, diff, V_PERPLAYER|V_ALLOWLOWERCASE|V_SNAPTORIGHT|V_HUDTRANS|map, "thin-right")
		end
	end
	
	-- Position tracker
	if circredux.cv_tracker.value and not (splitscreen and stplyr == consoleplayer) then
		local y = splitscreen and 99 or 187
		local align = (not splitscreen) and V_SNAPTOBOTTOM or 0
		circredux.DrawTracker(v, y, align)
	end
end)
